import {getRect} from '../common/utils'
import {VantComponent} from '../common/component'
import {isDef} from '../common/validator'
import {pageScrollMixin} from '../mixins/page-scroll'

const ROOT_ELEMENT = '.van-sticky'
VantComponent({
  props: {
    zIndex: {
      type: Number,
      value: 99,
    },
    offsetTop: {
      type: Number,
      value: 0,
      observer: 'onScroll',
    },
    disabled: {
      type: Boolean,
      observer: 'onScroll',
    },
    container: {
      type: null,
      observer: 'onScroll',
    },
    scrollTop: {
      type: null,
      observer(val) {
        this.onScroll({scrollTop: val})
      },
    },
  },
  mixins: [
    pageScrollMixin(function (event) {
      if (this.data.scrollTop != null) {
        return
      }
      this.onScroll(event)
    }),
  ],
  data: {
    height: 0,
    fixed: false,
    transform: 0,
  },
  mounted() {
    this.onScroll()
  },
  methods: {
    onScroll({scrollTop} = {}) {
      const {container, offsetTop, disabled} = this.data
      if (disabled) {
        this.setDataAfterDiff({
          fixed: false,
          transform: 0,
        })
        return
      }
      this.scrollTop = scrollTop || this.scrollTop
      if (typeof container === 'function') {
        Promise.all([getRect(this, ROOT_ELEMENT), this.getContainerRect()])
          .then(([root, container]) => {
            if (offsetTop + root.height > container.height + container.top) {
              this.setDataAfterDiff({
                fixed: false,
                transform: container.height - root.height,
              })
            } else if (offsetTop >= root.top) {
              this.setDataAfterDiff({
                fixed: true,
                height: root.height,
                transform: 0,
              })
            } else {
              this.setDataAfterDiff({fixed: false, transform: 0})
            }
          })
          .catch(() => {
          })
        return
      }
      getRect(this, ROOT_ELEMENT).then((root) => {
        if (!isDef(root) || (!root.width && !root.height)) {
          return
        }
        if (offsetTop >= root.top) {
          this.setDataAfterDiff({fixed: true, height: root.height})
          this.transform = 0
        } else {
          this.setDataAfterDiff({fixed: false})
        }
      })
    },
    setDataAfterDiff(data) {
      wx.nextTick(() => {
        const diff = Object.keys(data).reduce((prev, key) => {
          if (data[key] !== this.data[key]) {
            prev[key] = data[key]
          }
          return prev
        }, {})
        if (Object.keys(diff).length > 0) {
          this.setData(diff)
        }
        this.$emit('scroll', {
          scrollTop: this.scrollTop,
          isFixed: data.fixed || this.data.fixed,
        })
      })
    },
    getContainerRect() {
      const nodesRef = this.data.container()
      if (!nodesRef) {
        return Promise.reject(new Error('not found container'))
      }
      return new Promise((resolve) => nodesRef.boundingClientRect(resolve).exec())
    },
  },
})
